package gu.sql2java.utils;

import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.base.Strings.isNullOrEmpty;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.CaseFormat;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;

public class CaseSupport {

	/**
	 * @param name
	 * @return 将变量名转为蛇形命名法格式的字符串
	 */
	public static String toSnakecase(String name){
		return null == name ? name : CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,name);
	}

	/**
	 * @param name
	 * @return 将变量名转为驼峰命名法格式的字符串
	 */
	public static String toCamelcase(String name){
		return null == name ? name : CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name);
	}

	/**
	 * 如果是驼峰命名法格式,将变量名转为蛇形命名法格式的字符串
	 * @param name
	 * @since 3.30.0
	 */
	public static String toSnakecaseIfCamel(String name){
		return TO_SNAKE_CASE_IF_CAMEL.apply(name);
	}

	/**
	 * 如果是蛇形命名法格式将变量名转为驼峰命名法格式的字符串
	 * @param name
	 * @since 3.30.0
	 */
	public static String toCamelcaseIfSnake(String name){
		return TO_CAMEL_CASE_IF_SNAKE.apply(name) ;
	}

	/**
	 * 将输入字符串以separator分割后执行驼峰命名法到蛇形命名法的替换
	 * @param input
	 * @param separator 分割字符串
	 * @since 3.30.0
	 * @see #splitAndReplace(String, String, Function)
	 */
	public static String toSnakecaseIfCamel(String input,String separator){
		return splitAndReplace(input,separator,TO_SNAKE_CASE_IF_CAMEL);
	}
	/**
	 * 将输入字符串以separator或others定义的分割符分割后执行驼峰命名法到蛇形命名法的替换
	 * @param input
	 * @param separator 分割符
	 * @param others 定义多个分割符
	 * @since 3.30.0
	 * @see #splitAndReplace(String, CharMatcher, Function)
	 */
	public static String toSnakecaseIfCamel(String input,char separator,char... others){
		CharMatcher matcher = CharMatcher.is(separator);
		if(others !=null && others.length>0) {
			matcher = matcher.or(CharMatcher.anyOf(new String(others)));
		}
		return splitAndReplace(input,matcher,TO_SNAKE_CASE_IF_CAMEL);
	}
	/**
	 * 将输入字符串以separator分割后执行蛇形命名法到驼峰命名法的替换
	 * @param input
	 * @param separator 
	 * @since 3.30.0
	 * @see #splitAndReplace(String, String, Function)
	 */
	public static String toCamelcaseIfSnake(String input,String separator){
		return splitAndReplace(input,separator,TO_CAMEL_CASE_IF_SNAKE);
	}
	/**
	 * 将输入字符串以separator或others定义的分割符分割后执行蛇形命名法到驼峰命名法的替换
	 * @param input
	 * @param separator 分割符
	 * @param others 定义多个分割符
	 * @since 3.30.0
	 * @see #splitAndReplace(String, CharMatcher, Function)
	 */
	public static String toCamelcaseIfSnake(String input,char separator,char...others){
		CharMatcher matcher = CharMatcher.is(separator);
		if(others !=null && others.length>0) {
			matcher = matcher.or(CharMatcher.anyOf(new String(others)));
		}
		return splitAndReplace(input,matcher,TO_CAMEL_CASE_IF_SNAKE);
	}
	/**
	 * 将以'.'分割的嵌套字段名逐段执行驼峰命名法到蛇形命名法的替换
	 * @param input
	 * @since 3.30.0
	 * @see #splitAndReplace(String, CharMatcher, Function)
	 */
	public static String toNestedSnakecase(String input){
		return TO_NESTED_SNAKE_CASE.apply(input);
	}

	/**
	 * 将以'.'分割的嵌套字段名逐段执行蛇形命名法到驼峰命名法的替换
	 * @param input
	 * @since 3.30.0
	 * @see #splitAndReplace(String, CharMatcher, Function)
	 */
	public static String toNestedCamelcase(String input){
		return TO_NESTED_CAMEL_CASE.apply(input);
	}
	/**
	 * 将输入字符串以正则表达式分割符分割后执行驼峰命名法到蛇形命名法的替换
	 * @param input
	 * @param regex 正则表达式分割符
	 * @since 3.30.0
	 * @see #splitAndReplaceRegex(String, String, Function)
	 */
	public static String toSnakecaseIfCamelRegex(String input,String regex){
		return splitAndReplaceRegex(input,regex,TO_SNAKE_CASE_IF_CAMEL);
	}

	/**
	 * 将输入字符串以正则表达式分割符分割后执行蛇形命名法到驼峰命名法的替换
	 * @param input
	 * @param regex 正则表达式分割符
	 * @since 3.30.0
	 * @see #splitAndReplaceRegex(String, String, Function)
	 */
	public static String toCamelcaseIfSnakeRegex(String input,String regex){
		return splitAndReplaceRegex(input,regex,TO_CAMEL_CASE_IF_SNAKE);
	}

	/**
	 * 使用指定的分割符分割字符并使用replace指定函数对分割的字符串执行替换，返回替换后的字符串
	 * @param input
	 * @param separator
	 * @param replace
	 * @since 3.30.0
	 */
	public static String splitAndReplace(String input,String separator,Function<String, String>replace){
		if(!nullToEmpty(input).isEmpty() && null != replace){
			separator = nullToEmpty(separator);
			ArrayList<String> subnames = separator.isEmpty() 
					? Lists.newArrayList(input) 
					: Lists.newArrayList(Splitter.on(separator).split(input)) ;
			for(int i = 0; i < subnames.size() ; ++i) {
				subnames.set(i, replace.apply(subnames.get(i)));
			}
			return Joiner.on(separator).join(subnames);
		}
		return input;
	}
	/**
	 * 使用 charMatcher 指定的分割对象分割字符并使用replace指定函数对分割的字符串执行替换，返回替换后的字符串
	 * @param input
	 * @param charMatcher
	 * @param replace
	 * @since 3.30.0
	 */
	public static String splitAndReplace(String input,CharMatcher charMatcher,Function<String, String>replace){
		if(!nullToEmpty(input).isEmpty() && null != replace){
			if(null == charMatcher) {
				charMatcher = CharMatcher.none();
			}
		    // deal with camel conversion
		    StringBuilder out = null;
		    int i = 0, j = -1;
		    while ((j = charMatcher.indexIn(input, ++j)) != -1) {
		      if (i == 0) {
		        // include some extra space for separators
		        out = new StringBuilder(input.length());
		      }
		      if(j>i) {
		    	  out.append(replace.apply(input.substring(i, j)));
		      }
		      out.append(input.charAt(j));
		      i = j + 1;
		    }
		    return (i == 0)
		        ? replace.apply(input)
		        : out.append(replace.apply(input.substring(i))).toString();
		}
		return input;
	}

	/**
	 * 使用指定的正则表达式作分割符分割字符并使用replace指定函数对分割的字符串执行替换，返回替换后的字符串
	 * @param input
	 * @param regex
	 * @param replace
	 * @since 3.30.0
	 */
	public static String splitAndReplaceRegex(String input,String regex,Function<String, String>replace){
		if(!nullToEmpty(input).isEmpty() && null != replace){
			int index = 0;
			StringBuffer buffer = new StringBuffer();
			if(!isNullOrEmpty(regex)) {
				Matcher matcher = Pattern.compile(regex).matcher(input);
				while (matcher.find()) {
					if (index == 0 && index == matcher.start() && matcher.start() == matcher.end()) {
						// no empty leading substring included for zero-width match
						// at the beginning of the input char sequence.
						continue;
					}
					/** 替换分割符左侧字符串 */
					String left = replace.apply(input.substring(index, matcher.start()));
					buffer.append(left);
					buffer.append(matcher.group());
					/** 记录上一次匹配的末尾 */
					index = matcher.end();
				}
			}
			/** 替换最后一个分割符后面的字符串 */
			String last = replace.apply(input.substring(index));
			buffer.append(last);
			return buffer.toString();
		}
		return input;
	}
	private static final CharMatcher UPPERCASE_MATCHER = CharMatcher.inRange('A', 'Z');
	private static final CharMatcher LOWERCASE_MATCHER = CharMatcher.inRange('a', 'z');
	private static final CharMatcher DOT_MATCHER = CharMatcher.is('.');
	public static Function<String, String> TO_SNAKE_CASE_IF_CAMEL = new Function<String, String>() {
		@Override
		public String apply(String name) {
			if(isCamelcase(name)) {
				return toSnakecase(name);
			}
			return name;
		}
	};
	public static Function<String, String> TO_CAMEL_CASE_IF_SNAKE = new Function<String, String>() {
		@Override
		public String apply(String name) {
			if (isSnakecase(name)) {
				return toCamelcase(name);
			}
			return name ;
		}
	};
	public static Function<String, String> TO_NESTED_SNAKE_CASE = new Function<String, String>() {
		@Override
		public String apply(String input) {
			return splitAndReplace(input,DOT_MATCHER,TO_SNAKE_CASE_IF_CAMEL);
		}
	};
	public static Function<String, String> TO_NESTED_CAMEL_CASE = new Function<String, String>() {
		@Override
		public String apply(String input) {
			return splitAndReplace(input,DOT_MATCHER,TO_CAMEL_CASE_IF_SNAKE);
		}
	};
	/**
	 * 判断 变量是否为驼峰命名法格式的字符串
	 * @param input
	 */
	public static boolean isCamelcase(String input){
		if(!nullToEmpty(input).isEmpty()){
			return !input.equals(input.toLowerCase()) 
					&& !input.equals(input.toUpperCase()) && input.indexOf('_')<0; 
		}
		return false;
	}
	/**
	 * 判断 变量是否为驼峰命名法格式的字符串
	 * @param input
	 * @deprecated spell error,replaced by {@link #isSnakecase(String)}
	 */
	public static boolean isSnakelcase(String input){
		if(!nullToEmpty(input).isEmpty()){
			return input.indexOf('_')>=0;
		}
		return false ;
	}
	/**
	 * 判断 变量是否为驼峰命名法格式的字符串
	 * @param input
	 * @since 3.19.0
	 */
	public static boolean isSnakecase(String input){
		if(!nullToEmpty(input).isEmpty()){
			return input.indexOf('_')>=0;
		}
		return false ;
	}
	
    /**
     * 输入字符串中有大写字母则返回{@code true},否则返回{@code false}
     * @param input
     */
    public static boolean hasUpperCase(String input){
        return UPPERCASE_MATCHER.indexIn(nullToEmpty(input)) >= 0;
    }
    /**
     * 输入字符串中有小写字母则返回{@code true},否则返回{@code false}
     * @param input
     */
    public static boolean nonUpperCase(String input){
        return UPPERCASE_MATCHER.indexIn(nullToEmpty(input)) < 0;
    }
    /**
     * 输入字符串中有大写字母则返回{@code false},否则返回{@code false}
     * @param input
     */
    public static boolean hasLowerCase(String input){
    	return LOWERCASE_MATCHER.indexIn(nullToEmpty(input)) >= 0;
    }
    /**
     * 输入字符串中有小写字母则返回{@code false},否则返回{@code false}
     * @param input
     */
    public static boolean nonLowerCase(String input){
        return LOWERCASE_MATCHER.indexIn(nullToEmpty(input)) < 0;
    }
}